package com.kmxd.ams.app.arrange.command;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.kmxd.ams.client.archive.IArchiveFieldSvc;
import com.kmxd.ams.client.archive.IArchiveRuleMainSvc;
import com.kmxd.ams.client.archive.IArchiveTypeSvc;
import com.kmxd.ams.client.archive.dto.ArchiveFieldQueryDTO;
import com.kmxd.ams.client.archive.dto.RuleFieldQueryDTO;
import com.kmxd.ams.client.archive.vo.ArchiveFieldListVO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleFieldListVO;
import com.kmxd.ams.client.archive.vo.ArchiveRuleMainListVO;
import com.kmxd.ams.client.archive.vo.ArchiveTypeVO;
import com.kmxd.ams.client.arrange.IDocumentSvc;
import com.kmxd.ams.client.arrange.IProjectSvc;
import com.kmxd.ams.client.arrange.IVolumeSvc;
import com.kmxd.ams.client.arrange.dto.ChangeInVolumeArchCodeDTO;
import com.kmxd.ams.client.arrange.vo.ArchCodeVO;
import com.kmxd.ams.client.event.involume.ChangeInVolumeArchCodeEvent;
import com.kmxd.ams.client.system.ISysDictSvc;
import com.kmxd.ams.core.common.bo.DictModel;
import com.kmxd.ams.core.common.constant.ArchConst;
import com.kmxd.ams.core.common.constant.Constants;
import com.kmxd.ams.core.common.constant.ErrorCode;
import com.kmxd.ams.core.common.enums.*;
import com.kmxd.ams.core.exception.BizTipException;
import com.kmxd.ams.core.util.ConvertUtil;
import com.kmxd.ams.core.util.DynamicTableNameUtil;
import com.kmxd.ams.core.util.IdUtil;
import com.kmxd.ams.core.util.SecurityUtil;
import com.kmxd.ams.infra.archive.entity.ArchiveRuleMain;
import com.kmxd.ams.infra.archive.entity.ArchiveType;
import com.kmxd.ams.infra.arrange.base.SystemBO;
import com.kmxd.ams.infra.arrange.entity.Document;
import com.kmxd.ams.infra.arrange.entity.Project;
import com.kmxd.ams.infra.arrange.entity.Volume;
import com.kmxd.ams.infra.tmpl.dto.ArchTmplBO;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * 档号生成相关处理
 *
 * @author nickbi
 */
@Slf4j
@Component
@AllArgsConstructor
public class ArchCodeGenCmd {

  private final IArchiveRuleMainSvc archiveRuleMainSvc;
  private final IDocumentSvc documentSvc;
  private final IVolumeSvc volumeSvc;
  private final IArchiveTypeSvc archiveTypeSvc;
  private final IProjectSvc projectSvc;
  private final ExtendDataCmd extendDataCmd;
  private final IArchiveFieldSvc archiveFieldSvc;
  private final ISysDictSvc sysDictSvc;

  public ArchCodeVO archCode(Document req) {
    return archCode(req, null);
  }

  public <T extends SystemBO> ArchCodeVO refreshArchCode(T req, String saToken) {
    ArchCodeVO archCodeVO = ArchCodeVO.builder().build();
    //    // 设置继承数据信息  1、查询固定内容 -- 2、中间拼接符 -- 3、查询最新流水号
    RuleFieldQueryDTO fieldQueryDTO = BeanUtil.copyProperties(req, RuleFieldQueryDTO.class);
    setRuleByProjId(req.getArchTypeId(), req.getProjId(), fieldQueryDTO);
    ArchiveRuleMainListVO ruleMainListVO = archiveRuleMainSvc.getRuleMainByVersion(fieldQueryDTO);
    List<ArchiveRuleFieldListVO> lists = archiveRuleMainSvc.getRuleFieldByVersion(fieldQueryDTO);
    if (lists.isEmpty()) {
      return archCodeVO;
    }

    // 整理人可编号,所有人都可以生成档号

    // 各部门自行编号，个人角色不能请求档号
    Integer roleType =
        CharSequenceUtil.isBlank(saToken)
            ? SecurityUtil.getRoleType()
            : SecurityUtil.getRoleType(saToken);
    roleType = ObjectUtil.isEmpty(roleType) ? 1 : roleType;
    if (CollectWayEnum.COLLECT_DEPT_CODE.getCode().equals(ruleMainListVO.getCollectWay())
        && DataScopeTypeEnum.USER.getType().equals(roleType)) {
      return archCodeVO;
    }
    //  档案室集中编号，只有公司角色能生成档号
    if (CollectWayEnum.CONCENTRATED_CODE.getCode().equals(ruleMainListVO.getCollectWay())
        && !DataScopeTypeEnum.FONDS.getType().equals(roleType)) {
      return archCodeVO;
    }

    ArchiveFieldQueryDTO qryField = new ArchiveFieldQueryDTO();
    qryField.setTableId(req.getTableId());
    qryField.setDbFieldKeyList(
        lists.stream().map(ArchiveRuleFieldListVO::getFieldCode).collect(Collectors.toList()));
    List<ArchiveFieldListVO> fieldList = archiveFieldSvc.selectListByform(qryField);
    Map<String, ArchiveFieldListVO> fieldMap =
        fieldList.stream()
            .collect(Collectors.toMap(ArchiveFieldListVO::getDbFieldKey, Function.identity()));

    // 组装分组信息
    // 生成拼接部分内容
    StringBuffer sb = new StringBuffer();
    lists.forEach(
        item -> {
          String fieldCode = getFieldCode(item);
          // 固定字段
          if (NumberUtil.equals(RuleFieldTypeEnum.FIXED.getCode(), item.getType())) {
            sb.append(item.getFieldCode());
            // 流水号
            return;
          }
          // 字典等翻译后的档号拼接值
          String value =
              NumberUtil.equals(RuleFieldTypeEnum.FIXED.getCode(), item.getType())
                  ? fieldCode
                  : getValue(req, fieldCode, item.getDictField(), fieldMap);
          // 前缀拼接
          if (CharSequenceUtil.isNotBlank(item.getSpliceField())) {
            sb.append(item.getSpliceField());
          }
          // 空值，转换为空
          if (CharSequenceUtil.isBlank(value)) {
            value = ArchConst.ARCH_CODE_NULL_VALUE;
          }
          // 拼接元数据值
          if (ImmutableSet.of(ArchConst.DOC_SEQUENCE_DB, ArchConst.VOL_SEQUENCE_DB)
              .contains(item.getFieldCode())) {
            Integer codeLen = getCodeLengthWithTableId(ruleMainListVO, req.getTableId());
            String code = IdUtil.autoGenCode(value, codeLen, false);
            if (ObjectUtil.isNotEmpty(value) && ObjectUtil.notEqual("0", value)) {
              sb.append(code);
              archCodeVO.setSequence(Integer.valueOf(code));
            }
          } else {
            sb.append(value);
          }
        });
    archCodeVO.setArchCode(sb.toString());
    return archCodeVO;
  }

  private static String getFieldCode(ArchiveRuleFieldListVO item) {
    return !StringUtils.isCamel(item.getFieldCode())
        ? StringUtils.underlineToCamel(item.getFieldCode())
        : item.getFieldCode();
  }

  public <T extends SystemBO> ArchCodeVO archCode(T req, String saToken) {
    ArchCodeVO archCodeVO = ArchCodeVO.builder().build();
    //    // 设置继承数据信息  1、查询固定内容 -- 2、中间拼接符 -- 3、查询最新流水号
    RuleFieldQueryDTO fieldQueryDTO = BeanUtil.copyProperties(req, RuleFieldQueryDTO.class);
    setRuleByProjId(req.getArchTypeId(), req.getProjId(), fieldQueryDTO);
    ArchiveRuleMainListVO ruleMainListVO = archiveRuleMainSvc.getRuleMainByVersion(fieldQueryDTO);
    List<ArchiveRuleFieldListVO> lists = archiveRuleMainSvc.getRuleFieldByVersion(fieldQueryDTO);
    if (lists.isEmpty()) {
      return archCodeVO;
    }

    // 整理人可编号,所有人都可以生成档号

    // 各部门自行编号，个人角色不能请求档号
    Integer roleType =
        CharSequenceUtil.isBlank(saToken)
            ? SecurityUtil.getRoleType()
            : SecurityUtil.getRoleType(saToken);
    roleType = ObjectUtil.isEmpty(roleType) ? 1 : roleType;
    if (CollectWayEnum.COLLECT_DEPT_CODE.getCode().equals(ruleMainListVO.getCollectWay())
        && DataScopeTypeEnum.USER.getType().equals(roleType)) {
      return archCodeVO;
    }
    //  档案室集中编号，只有公司角色能生成档号
    if (CollectWayEnum.CONCENTRATED_CODE.getCode().equals(ruleMainListVO.getCollectWay())
        && !DataScopeTypeEnum.FONDS.getType().equals(roleType)) {
      return archCodeVO;
    }

    ArchiveFieldQueryDTO qryField = new ArchiveFieldQueryDTO();
    qryField.setTableId(req.getTableId());
    qryField.setDbFieldKeyList(
        lists.stream().map(ArchiveRuleFieldListVO::getFieldCode).collect(Collectors.toList()));
    List<ArchiveFieldListVO> fieldList = archiveFieldSvc.selectListByform(qryField);
    Map<String, ArchiveFieldListVO> fieldMap =
        fieldList.stream()
            .collect(Collectors.toMap(ArchiveFieldListVO::getDbFieldKey, Function.identity()));
    // 继承信息不再复制
    //    Map<String, Object> extendData = extendDataCmd.buildExtendData(req);
    //    BeanUtil.copyProperties(extendData, req, CopyOptions.create().ignoreNullValue());

    Map<String, Object> columnMap = new HashMap<>();
    // 获取新档号，排除当前规则
    if (ObjectUtil.isNotEmpty(req.getId())) {
      String idsField =
          CharSequenceUtil.contains(req.getTableId(), ArchTmplBO.DOCUMENT)
              ? ArchConst.DOC_IDS
              : ArchConst.VOL_IDS;
      columnMap.put(idsField, req.getId());
    }
    // 组装分组信息
    // 生成拼接部分内容
    StringBuffer sb = new StringBuffer();

    lists.forEach(
        item -> {
          String fieldCode =
              !StringUtils.isCamel(item.getFieldCode())
                  ? StringUtils.underlineToCamel(item.getFieldCode())
                  : item.getFieldCode();

          // 设置流水查询字段
          // 启用分组字段
          // 原始数据值
          String fieldValue = JSONUtil.parseObj(req).getStr(fieldCode);
          if (BooleanUtil.isTrue(item.getEnableGroup())
              && CharSequenceUtil.isNotBlank(fieldValue)) {
            columnMap.put(item.getFieldCode(), fieldValue);
          }

          appendArchCode(req, archCodeVO, ruleMainListVO, columnMap, fieldMap, sb, item);
        });
    archCodeVO.setArchCode(sb.toString());
    return archCodeVO;
  }

  private <T extends SystemBO> void appendArchCode(
      T req,
      ArchCodeVO archCodeVO,
      ArchiveRuleMainListVO ruleMainListVO,
      Map<String, Object> columnMap,
      Map<String, ArchiveFieldListVO> fieldMap,
      StringBuffer sb,
      ArchiveRuleFieldListVO item) {

    String fieldCode = getFieldCode(item);
    // 固定字段
    if (NumberUtil.equals(RuleFieldTypeEnum.FIXED.getCode(), item.getType())) {
      sb.append(item.getFieldCode());
      // 流水号
      return;
    }
    // 字典等翻译后的档号拼接值
    String value =
        NumberUtil.equals(RuleFieldTypeEnum.FIXED.getCode(), item.getType())
            ? fieldCode
            : getValue(req, fieldCode, item.getDictField(), fieldMap);
    // 前缀拼接
    if (CharSequenceUtil.isNotBlank(item.getSpliceField())) {
      sb.append(item.getSpliceField());
    }
    // 流水字段
    if (ImmutableSet.of(ArchConst.DOC_SEQUENCE, ArchConst.VOL_SEQUENCE).contains(fieldCode)) {
      // 获取流水部分内容
      String sequence;
      if (ObjectUtil.isNotEmpty(value)) {
        sequence = buildInputSequence(NumberUtil.parseInt(value));
      } else {
        sequence =
            CharSequenceUtil.contains(req.getTableId(), ArchTmplBO.DOCUMENT)
                ? documentSvc.getSequence(columnMap, req.getTableId())
                : volumeSvc.getSequence(columnMap, req.getTableId(), false);
      }
      Integer codeLen = getCodeLengthWithTableId(ruleMainListVO, req.getTableId());
      String code = IdUtil.autoGenCode(sequence, codeLen);
      archCodeVO.setSequence(NumberUtil.parseInt(sequence) + 1);
      sb.append(code);
      return;
    }
    // 拼接元数据值
    if (CharSequenceUtil.isBlank(value)) {
      value = ArchConst.ARCH_CODE_NULL_VALUE;
    }
    sb.append(value);
  }

  /**
   * 通过TableId获取流水长度
   *
   * @param ruleMainListVO
   * @param tableId
   * @return
   */
  private Integer getCodeLengthWithTableId(ArchiveRuleMainListVO ruleMainListVO, String tableId) {
    Integer codeLen = ruleMainListVO.getCodeLen();
    if (CharSequenceUtil.contains(tableId, ArchTmplBO.VOLUME)) {
      codeLen = ruleMainListVO.getVolCodeLen();
    }
    if (CharSequenceUtil.contains(tableId, ArchTmplBO.BOX)) {
      codeLen = ruleMainListVO.getBoxCodeLen();
    }
    return codeLen;
  }

  public ArchCodeVO archCode(Volume req) {
    return archCode(req, null);
  }

  /**
   * 获取doc对象的值
   *
   * @param document
   * @param fieldKey
   * @return
   */
  private String getValue(
      Object document,
      String fieldKey,
      String dictField,
      Map<String, ArchiveFieldListVO> fieldMap) {
    String originFieldKey = fieldKey;
    ArchiveFieldListVO field = fieldMap.get(StringUtils.camelToUnderline(originFieldKey));
    // 字典项分组字段
    if (StrUtil.isNotBlank(field.getDictField())) {
      JSONObject jsonObject = JSONUtil.parseObj(document);
      String fieldValue = jsonObject.getStr(originFieldKey);
      if (StrUtil.isBlank(fieldValue)) {
        return null;
      }
      // 查询字典信息
      String setCode = null;
      // 密级跟多系列多版本相关，传递setCode
      if (ArchConst.FIELD_SECURITY.equals(originFieldKey)) {
        ArchiveType archiveType =
            archiveTypeSvc.getById(getFieldValue(document, ArchConst.ARCH_TYPE_ID));
        setCode = archiveType.getSecretCodeId();
      }
      // 保管期限跟多系列相关，传递setCode

      ArchiveTypeVO archiveType =
          archiveTypeSvc.view(Long.parseLong(getFieldValue(document, ArchConst.ARCH_TYPE_ID)));
      if (ArchConst.FIELD_RETENTION_PERIOD.equals(originFieldKey)) {
        setCode = archiveType.getRpCodeId();
      }

      String yearStr = getFieldValue(document, ArchConst.FIELD_YEAR);
      int year =
          StrUtil.isNotBlank(yearStr) && NumberUtil.isNumber(yearStr)
              ? Integer.parseInt(yearStr)
              : Constants.DEF_VERSION;

      // 将符合条件的字典项都查询出来，后面再进行过滤筛选
      List<DictModel<String>> dictModels =
          sysDictSvc.listDictModel(
              field.getDictField(),
              setCode,
              year,
              DictValueEnum.STRING,
              null,
              archiveType.getComId());

      if (ObjectUtil.isEmpty(dictModels)) {
        throw BizTipException.instance(ErrorCode.DICT_NOT_FOUND, "字典未找到");
      }
      // 按年度过滤筛选后找到字典值
      Optional<DictModel<String>> first =
          dictModels.stream()
              .filter(
                  item ->
                      Objects.equals(
                          getFieldValue(
                              item,
                              StrUtil.isBlank(field.getDictStorage())
                                  ? DictStorageEnum.VALUE.getType()
                                  : field.getDictStorage()),
                          fieldValue))
              .findFirst();
      if (first.isPresent()) {
        DictModel<String> dictModel = first.get();
        // 按分组设置，返回code 或者value 的值
        if (dictField.equals(DictStorageEnum.VALUE.getType())) {
          return dictModel.getValue();
        } else {
          return dictModel.getLabel();
        }
      } else {
        return null;
      }
    }
    JSONObject jsonObject = JSONUtil.parseObj(document);
    return jsonObject.getStr(fieldKey);
  }

  private String getFieldValue(Object source, String fieldKey) {
    try {
      if (StrUtil.isBlank(fieldKey)) {
        return null;
      }
      JSONObject jsonObject = JSONUtil.parseObj(source);
      return jsonObject.getStr(fieldKey);
    } catch (Exception e) {
      return null;
    }
  }

  public ArchiveRuleMain getRuleInfo(Long archTypeId, Long projId, Integer year) {
    // 项目下案卷，整理规则以项目整理规则为准
    ArchiveTypeVO archInfo =
        Optional.ofNullable(archiveTypeSvc.view(archTypeId))
            .orElseThrow(() -> BizTipException.instance(ErrorCode.NOT_FOUND, "未找到门类信息"));
    if (Objects.nonNull(projId) && BooleanUtil.isTrue(archInfo.getHaveProject())) {
      Project qry = new Project();
      qry.setId(projId);
      String projTableId = archInfo.getProjTableId();
      qry.setTableId(projTableId);
      Project project =
          Optional.ofNullable(projectSvc.view(qry))
              .orElseThrow(() -> BizTipException.instance(ErrorCode.NOT_FOUND, "未找到项目信息"));
      Long archRuleId = project.getArchRuleId();
      return archiveRuleMainSvc.getById(archRuleId);
    }
    // 普通案卷
    RuleFieldQueryDTO qryRuleMain = new RuleFieldQueryDTO();
    qryRuleMain.setYear(year);
    qryRuleMain.setArchTypeId(archTypeId);
    ArchiveRuleMainListVO ruleMainByVersion = archiveRuleMainSvc.getRuleMainByVersion(qryRuleMain);
    return ConvertUtil.toBean(ruleMainByVersion, ArchiveRuleMain.class);
  }

  public void refreshDocumentArchCode(ChangeInVolumeArchCodeEvent event) {
    ChangeInVolumeArchCodeDTO req = event.getReq();
    DynamicTableNameUtil.setTableName(req.getTableId());
    List<Volume> volumeList = volumeSvc.selectListByIds(IdUtil.split(req.getVolIds()));
    if (ObjectUtil.isEmpty(volumeList)) {
      throw BizTipException.instance(ErrorCode.NOT_FOUND, "未找到案卷信息");
    }
    volumeList.forEach(
        volume ->
            CompletableFuture.runAsync(
                () ->
                    refreshInVolumeArchCode(
                        volume, req.getArchTypeId(), event.getSaToken(), req.getUpdateSequence())));
  }

  public void refreshInVolumeArchCode(
      Volume volume, Long archTypeId, String saToken, Boolean updateSequence) {
    ArchiveRuleMain ruleInfo = getRuleInfo(archTypeId, volume.getProjId(), volume.getYear());
    ArchiveTypeVO archInfo =
        Optional.ofNullable(archiveTypeSvc.view(archTypeId))
            .orElseThrow(() -> BizTipException.instance(ErrorCode.NOT_FOUND, "未找到门类信息"));
    // 不是科室自己编号，直接返回，不更新文件档号信息
    // 整理人可编号,所有人都可以生成档号

    // 各部门自行编号，个人角色不能请求档号
    if (CollectWayEnum.COLLECT_DEPT_CODE.getCode().equals(ruleInfo.getCollectWay())
        && DataScopeTypeEnum.USER.getType().equals(SecurityUtil.getRoleType(saToken))) {
      return;
    }
    //  档案室集中编号，只有公司角色能生成档号
    if (CollectWayEnum.CONCENTRATED_CODE.getCode().equals(ruleInfo.getCollectWay())
        && !DataScopeTypeEnum.FONDS.getType().equals(SecurityUtil.getRoleType(saToken))) {
      return;
    }
    RuleFieldQueryDTO qryRuleField = new RuleFieldQueryDTO();
    qryRuleField.setRuleId(ruleInfo.getId());
    List<ArchiveRuleFieldListVO> ruleList = archiveRuleMainSvc.getRuleFieldByVersion(qryRuleField);
    Map<String, Object> syncVolumeData = getSyncVolumeData(ruleList, volume);

    // 查询文档扩展数据
    Document qryExtendData = new Document();
    qryExtendData.setTableId(archInfo.getDocTableId());
    qryExtendData.setVolId(volume.getId());
    Map<String, Object> extendData = extendDataCmd.buildExtendData(qryExtendData);
    // 查询文档分页数据
    Document qryPage = new Document();
    qryPage.setTableId(archInfo.getDocTableId());
    qryPage.setVolId(volume.getId());
    qryPage.setStatus(volume.getStatus());
    AtomicInteger pageIndex = new AtomicInteger(Constants.FIRST_PAGE);
    AtomicInteger sequence = new AtomicInteger(1);
    while (true) {
      Page<Document> page = new Page<>(pageIndex.getAndIncrement(), Constants.DEF_BATCH_PAGE_SIZE);
      DynamicTableNameUtil.setTableName(archInfo.getDocTableId());
      Page<Document> documentPage = documentSvc.selectPage(page, qryPage);
      if (ObjectUtil.isEmpty(documentPage) || ObjectUtil.isEmpty(documentPage.getRecords())) {
        return;
      }

      documentPage
          .getRecords()
          .forEach(
              document -> {
                // 档号信息与当前案卷一致，不进行档号更新
                //                if (StrUtil.isNotBlank(document.getArchCode())
                //                    && StrUtil.isNotBlank(volume.getArchCode())
                //                    && document.getArchCode().contains(volume.getArchCode())) {
                //                  return;
                //                }

                // 继承信息不再进行复制 !!!
                BeanUtil.copyProperties(
                    extendData, document, CopyOptions.create().ignoreNullValue());

                BeanUtil.copyProperties(syncVolumeData, document);
                document.setVolId(volume.getId());
                document.setArchTypeId(archTypeId);
                document.setTableId(archInfo.getDocTableId());
                if (BooleanUtil.isTrue(updateSequence)) {
                  document.setDocSequence(sequence.getAndIncrement());
                }
                ArchCodeVO archCodeVO = archCode(document, saToken);
                document.setArchCode(archCodeVO.getArchCode());
                document.setDocSequence(archCodeVO.getSequence());
                document.setArchCode(archCodeVO.getArchCode());
                document.setDocSequence(archCodeVO.getSequence());
              });
      DynamicTableNameUtil.setTableName(archInfo.getDocTableId());
      documentSvc.updateBatchById(page.getRecords());
    }
  }

  private Map<String, Object> getSyncVolumeData(
      List<ArchiveRuleFieldListVO> ruleList, Volume volume) {
    Map<String, Object> volumeMap = BeanUtil.beanToMap(volume);
    List<String> fieldSet =
        ruleList.stream()
            .filter(f -> f.getTableId().contains(ArchTmplBO.VOLUME))
            .filter(ArchiveRuleFieldListVO::getEnableGroup)
            .filter(f -> !f.getFieldCode().contains(ArchConst.SEQUENSE))
            .map(rule -> StringUtils.underlineToCamel(rule.getFieldCode()))
            .collect(Collectors.toList());
    return fieldSet.stream()
        .map(
            filed -> {
              Map<String, Object> map = Maps.newHashMap();
              map.put(filed, volumeMap.get(filed));
              return map;
            })
        .flatMap(e -> e.entrySet().stream())
        .collect(HashMap::new, (m, v) -> m.put(v.getKey(), v.getValue()), HashMap::putAll);
  }

  private String buildInputSequence(Integer sequence) {
    if (Objects.isNull(sequence)) {
      return "0";
    }
    int value = sequence > 0 ? sequence - 1 : 0;
    return String.valueOf(value);
  }

  private void setRuleByProjId(Long archTypeId, Long projId, RuleFieldQueryDTO fieldQueryDTO) {
    if (Objects.nonNull(projId)) {
      ArchiveType archiveType = archiveTypeSvc.getById(archTypeId);
      if (Objects.isNull(archiveType)) {
        return;
      }
      Project qry = new Project();
      qry.setArchTypeId(archiveType.getId());
      qry.setId(projId);
      qry.setTableId(archiveType.getProjTableId());
      Project project = projectSvc.view(qry);
      fieldQueryDTO.setRuleId(project.getArchRuleId());
    }
  }
}
